{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# bqplot: complex interactive visualizations\n",
    "\n",
    "## https://github.com/bloomberg/bqplot\n",
    "\n",
    "## A Jupyter - d3.js bridge\n",
    "\n",
    "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n",
    "\n",
    "- Apache Licensed\n",
    "\n",
    "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n",
    "\n",
    "bqplot provides both\n",
    "-\thigh-level plotting procedures with relevant defaults for common chart types,\n",
    "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge bqplot\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "from IPython.display import display\n",
    "from ipywidgets import *\n",
    "from traitlets import *\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import bqplot as bq\n",
    "import datetime as dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(0)\n",
    "size = 100\n",
    "y_data = np.cumsum(np.random.randn(size) * 100.0)\n",
    "y_data_2 = np.cumsum(np.random.randn(size))\n",
    "y_data_3 = np.cumsum(np.random.randn(size) * 100.)\n",
    "\n",
    "x = np.linspace(0.0, 10.0, size)\n",
    "\n",
    "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,\n",
    "                          columns=['Security 1', 'Security 2'],\n",
    "                          index=pd.date_range(start='01-01-2007', periods=150))\n",
    "\n",
    "symbol = 'Security 1'\n",
    "dates_all = price_data.index.values\n",
    "final_prices = price_data[symbol].values.flatten()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A simple plot with the pyplot API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bqplot import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(1)\n",
    "n = 100\n",
    "plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), \n",
    "         axes_options={'y': {'grid_lines': 'dashed'}})\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Scatter Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(title='Scatter Plot with colors')\n",
    "plt.scatter(y_data_2, y_data_3, color=y_data)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Histogram"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure()\n",
    "plt.hist(y_data, colors=['OrangeRed'])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Every component of the figure is an independent widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x = np.arange(100)\n",
    "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n",
    "\n",
    "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n",
    "\n",
    "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# update data of the line mark\n",
    "line.y = np.cumsum(np.random.randn(2, 100), axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x, y = np.random.rand(2, 20)\n",
    "scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n",
    "\n",
    "fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#data updates\n",
    "scatt.x = np.random.rand(20) * 10\n",
    "scatt.y = np.random.rand(20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The same holds for the attributes of scales, axes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs.min = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs.min = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xax.label = 'Some label for the x axis'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Use bqplot figures as input widgets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x = np.arange(100)\n",
    "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n",
    "\n",
    "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Selections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def interval_change_callback(change):\n",
    "    db.value = str(change['new'])\n",
    "\n",
    "intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])\n",
    "intsel.observe(interval_change_callback, names=['selected'] )\n",
    "\n",
    "db = widgets.Label()\n",
    "db.value = str(intsel.selected)\n",
    "display(db)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "line.selected"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Handdraw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "handdraw = bq.interacts.HandDraw(lines=line)\n",
    "fig.interaction = handdraw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "line.y[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Moving points around"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bqplot import (LinearScale, Scatter, Label, Axis, Figure, Lines)\n",
    "import numpy as np\n",
    "\n",
    "size = 100\n",
    "np.random.seed(0)\n",
    "x_data = range(size)\n",
    "y_data = np.cumsum(np.random.randn(size) * 100.0)\n",
    "\n",
    "## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and \n",
    "## notice the line representing the mean of the data update\n",
    "\n",
    "sc_x = LinearScale()\n",
    "sc_y = LinearScale()\n",
    "\n",
    "scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],\n",
    "               enable_move=True)\n",
    "lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])\n",
    "m = Label(x=[0.05], y=[0.9], text=[\"\"], colors=[\"black\"])\n",
    "\n",
    "def update_line(change):\n",
    "    with lin.hold_sync():\n",
    "        lin.x = [np.min(scat.x), np.max(scat.x)]\n",
    "        lin.y = [np.mean(scat.y), np.mean(scat.y)]\n",
    "        m.text=['Mean is %s'%np.mean(scat.y)]\n",
    "        \n",
    "\n",
    "update_line(None)\n",
    "\n",
    "# update line on change of x or y of scatter\n",
    "scat.observe(update_line, names='x')\n",
    "scat.observe(update_line, names='y')\n",
    "\n",
    "ax_x = Axis(scale=sc_x)\n",
    "ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')\n",
    "\n",
    "fig = Figure(marks=[scat, lin, m], axes=[ax_x, ax_y])\n",
    "\n",
    "## In this case on drag, the line updates as you move the points.\n",
    "with scat.hold_sync():\n",
    "    scat.enable_move = True\n",
    "    scat.update_on_move = True\n",
    "    scat.enable_add = False\n",
    "\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1) Create a line chart using the object model (use x_data and y_data as your data attributes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2) Update the data of the Line mark, and change its color to 'darkorange'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  },
  "widgets": {
   "state": {
    "0ba98b0561564e5987dba19d1b574c04": {
     "views": [
      {
       "cell_index": 29
      }
     ]
    },
    "1ffa1ac6658e4eef89e45cf62daae339": {
     "views": [
      {
       "cell_index": 30
      }
     ]
    },
    "42735872becb4c43b817ccff90973d63": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "4b9a5b18593545faba761a719b2e6039": {
     "views": [
      {
       "cell_index": 17
      }
     ]
    },
    "7fb14b25d15240ec820c565619fe4f11": {
     "views": [
      {
       "cell_index": 7
      }
     ]
    },
    "99604f1b70c54e19a508c95d705ce488": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "bf805af773d94496888afbe9e2bd3d37": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "dc1b84a0e5fa4ed5a42454cfc52c44f5": {
     "views": [
      {
       "cell_index": 25
      }
     ]
    },
    "f30275bcf69e426c9d45a525833198d0": {
     "views": [
      {
       "cell_index": 5
      }
     ]
    }
   },
   "version": "2.0.0-dev"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
